#ifndef _NE_TEST_FSM_H_
#define _NE_TEST_FSM_H_

#include <common/FiniteStateMachine.h>

namespace ne
{
    // TODO: If you need to call some of your custom interfaces
    //       in your custom derived FSM
    //       you must define your custom derived FSM here
    //       and define friend class
    // class TestFSM;

    class TestState : public State<real>
    {
        // TODO: If you need to call some of your custom interfaces
        //       in your custom derived FSM
        //       you must define friend class here
        // friend class TestFSM;

        public:
            explicit TestState(real *pContent, const uint32_t id=FINITE_STATE_MACHINE_DEFAULT_STATE_ID)
                : State<real>(pContent, id)
            {
            }

        protected:
            virtual uint32_t onEvent(Event &event)
            {
                std::cout << "TestState Default: " << *mpContent << std::endl;
                return mID;
            }

            virtual ~TestState()
            {
            }
    };

    class TestState1 : public TestState
    {
        public:
            explicit TestState1(real *pContent)
                : TestState(pContent, 1)
            {
            }

        protected:
            virtual uint32_t onEvent(Event &event)
            {
                std::cout << "TestState 1: " << *mpContent << std::endl;
                *mpContent += 0.131f;
                if (*mpContent >= 2.0f)
                {
                    return 2;
                }
                return mID;
            }

            virtual bool onEnter(Event &event, const uint32_t lastStateID)
            {
                *mpContent = 1.0f;
                return true;
            }

            virtual bool onLoop(Event &event)
            {
                return true;
            }

            virtual bool onExit(Event &event, const uint32_t nextStateID)
            {
                return true;
            }

            virtual ~TestState1()
            {
            }
    };

    class TestState2 : public TestState
    {
        public:
            explicit TestState2(real *pContent)
                : TestState(pContent, 2)
            {
            }

        protected:
            virtual uint32_t onEvent(Event &event)
            {
                std::cout << "TestState 2: " << *mpContent << std::endl;
                *mpContent += 0.113f;
                if (*mpContent >= 3.0f)
                {
                    return FINITE_STATE_MACHINE_DEFAULT_STATE_ID;
                }
                return mID;
            }

            virtual bool onEnter(Event &event, const uint32_t lastStateID)
            {
                *mpContent = 2.0f;
                return true;
            }

            virtual bool onLoop(Event &event)
            {
                return true;
            }

            virtual bool onExit(Event &event, const uint32_t nextStateID)
            {
                return true;
            }

            virtual ~TestState2()
            {
            }
    };

    class TestFSM : public FiniteStateMachine<real>
    {
        public:
            explicit TestFSM(real *pContent)
                : FiniteStateMachine<real>(pContent)
            {
                // TODO: If you write your custom derived DefaultState
                //       you must call reset() here
                //       or the first state of the FSM will be the base DefaultState
            }

            // TODO: Also can write as
            // virtual State<T>* createState(const uint32_t stateID)
            virtual TestState* createState(const uint32_t stateID)
            {
                TestState *pState = 0;
                switch (stateID)
                {
                    case FINITE_STATE_MACHINE_DEFAULT_STATE_ID:
                    {
                        pState = createDefaultState();
                        break;
                    }
                    case 1:
                    {
                        pState = new TestState1(mpContent);
                        break;
                    }
                    case 2:
                    {
                        pState = new TestState2(mpContent);
                        break;
                    }
                    default:
                    {
                        pState = createDefaultState();
                        break;
                    }
                }
                return pState;
            }

            // TODO: Also can write as
            // virtual State<T>* createDefaultState()
            virtual TestState* createDefaultState()
            {
                return new TestState(mpContent);
            }

            virtual ~TestFSM()
            {
            }
    };
}

#endif
